package io.renren.common.utils;

import com.aliyun.oss.ServiceException;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.renren.modules.generator.entity.EnterpriseThirdBindRecordEntity;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhengd
 */
public class Sign {

    //token中包含的参数，可自行添加
    public static final String CLAIM_USER_ID = "userId";

    public static final String CLAIM_DEPT_ID = "deptId";

    public static final String CLAIM_USER_NO = "userNo";

    public static final String CLAIM_USER_NAME = "userName";

    public static final String CLAIM_ROLE_CODE = "roleCode";

    public static final String CLAIM_ROLE_NAME = "roleName";

    public static final String CLAIM_DEPT_NAME = "deptName";

    private static Map<String, JWTVerifier> verifierMap = new HashMap<>();
    private static Map<String, Algorithm> algorithmMap = new HashMap<>();

    /**
     * 生成Token
     *
     * @param userDto      用户信息
     * @param signingToken 密钥
     * @param duration     过期时间
     * @return token
     */
    public static String generateSessionToken(EnterpriseThirdBindRecordEntity userDto, String signingToken, long duration) {
        if (StringUtils.isEmpty(signingToken)) {
            throw new ServiceException("No signing token present");
        }
        Algorithm algorithm = getAlgorithm(signingToken);
        String token = JWT.create()
                .withClaim(CLAIM_USER_ID, userDto.getUserId())
                .withClaim(CLAIM_USER_NO, userDto.getUserNo())
                .withClaim(CLAIM_USER_NAME, userDto.getUserName())
                .withClaim(CLAIM_ROLE_CODE, userDto.getRoleCode())
                .withClaim(CLAIM_ROLE_NAME, userDto.getRoleName())
                .withClaim(CLAIM_DEPT_ID, userDto.getDeptId())
                .withClaim(CLAIM_DEPT_NAME, userDto.getDeptName())
                .withExpiresAt(new Date(System.currentTimeMillis() + duration))
                .sign(algorithm);
        return token;
    }

    /**
     * 校验token
     *
     * @param tokenString  token
     * @param signingToken 密钥
     * @return
     */
    public static DecodedJWT verifySessionToken(String tokenString, String signingToken) {
        return verifyToken(tokenString, signingToken);
    }

    static DecodedJWT verifyToken(String tokenString, String signingToken) {
        JWTVerifier verifier = verifierMap.get(signingToken);
        if (verifier == null) {
            synchronized (verifierMap) {
                verifier = verifierMap.get(signingToken);
                if (verifier == null) {
                    Algorithm algorithm = Algorithm.HMAC512(signingToken);
                    verifier = JWT.require(algorithm).build();
                    verifierMap.put(signingToken, verifier);
                }
            }
        }
        DecodedJWT jwt = verifier.verify(tokenString);
        return jwt;
    }

    private static Algorithm getAlgorithm(String signingToken) {
        Algorithm algorithm = algorithmMap.get(signingToken);
        if (algorithm == null) {
            synchronized (algorithmMap) {
                algorithm = algorithmMap.get(signingToken);
                if (algorithm == null) {
                    algorithm = Algorithm.HMAC512(signingToken);
                    algorithmMap.put(signingToken, algorithm);
                }
            }
        }
        return algorithm;
    }

}
